#include "Automato.h"
#include "Estado.h"
#include "Transicao.h"
#include <vector>
#include <list>

Automato::Automato() {

}

Automato::Automato(char caractere) {
    criarTransicaoInicial(caractere);
}



void Automato::criarTransicaoInicial(char caractere) {

    Estado estado0 = Estado();
    estado0.setEstadoFinal(false);
    Transicao transicao1 = Transicao(caractere, 1);
    //    transicao1.setCaracterLido(caractere);
    //    transicao1.setProxEstado(1);
    estado0.addTransicao(transicao1);
    this->addEstado(estado0);

    Estado estado1 = Estado();
    estado1.setEstadoFinal(true);
    this->addEstado(estado1);

    this->setEstadoInicial(0);
}

void Automato::setEstadoInicial(int estadoInicial) {
    this->_estadoInicial = estadoInicial;
}

int Automato::getEstadoInicial() {
    return _estadoInicial;
}

void Automato::addEstado(Estado estado) {
    this->_listaEstados.push_back(estado);
}

list<Estado> Automato::getListaEstados() {
    return this->_listaEstados;
}

Automato Automato::RealizarConcatenacao(Automato automato) {

    Automato automatoAux = Automato();


    list<Estado> listaEstados = this->getListaEstados();

    list<Estado>::iterator iterator;

    for (iterator = listaEstados.begin(); iterator != listaEstados.end(); ++iterator) {

        Estado estado = Estado();

        estado.setListaTransicoes(iterator->getListaTransicoes());

        if (iterator->isEstadoFinal()) {
            Transicao transicao = Transicao('&', this->getListaEstados().size());
            estado.addTransicao(transicao);
        }

        estado.setEstadoFinal(false);
        automatoAux.addEstado(estado);
    }

    listaEstados = automato.getListaEstados();
    for (iterator = automato.getListaEstados().begin(); iterator != listaEstados.end(); ++iterator) {
        Estado estado = Estado();

        list<Transicao>::iterator iterator2;
        list<Transicao> listaTransicoes = iterator->getListaTransicoes();

        for (iterator2 = listaTransicoes.begin(); iterator2 != listaTransicoes.end(); ++iterator2) {
            estado.addTransicao(Transicao(iterator2->getCaracterLido(),
                    iterator2->getProxEstado() + this->getListaEstados().size()));
        }

        estado.setEstadoFinal(iterator->isEstadoFinal());
        automatoAux.addEstado(estado);


    }
    automatoAux.setEstadoInicial(this->getEstadoInicial());

    return automatoAux;

}

Automato Automato::RealizarOu() {

    Transicao transicao = Transicao();
    transicao.setCaracterLido('&');
    transicao.setProxEstado(1);

    Estado estado = Estado();
    estado.setEstadoFinal(false);
    estado.addTransicao(transicao);

    Automato automato = Automato();
    automato.addEstado(estado);


    list<Estado> listaEstados = this->getListaEstados();
    list<Estado>::iterator iterator1;

    for (iterator1 = listaEstados.begin(); iterator1 != listaEstados.end(); ++iterator1) {
        Estado estado2 = Estado();
        list<Transicao> listaTransicoes = iterator1->getListaTransicoes();

        list<Transicao>::iterator iterator2;

        for (iterator2 = listaTransicoes.begin(); iterator2 != listaTransicoes.end(); ++iterator2) {
            Transicao transicao = Transicao(iterator2->getCaracterLido(),
                    iterator2->getProxEstado() + 1);
            estado2.addTransicao(transicao);
        }

        if (iterator1->isEstadoFinal()) {
            Transicao transicao = Transicao('&', 1);
            estado2.addTransicao(transicao);
            transicao = Transicao('&', this->getListaEstados().size() + 1);
            estado2.addTransicao(transicao);
        }

        estado2.setEstadoFinal(false);
        automato.addEstado(estado2);
    }

    Estado estadoFinal = Estado();

    estadoFinal.setEstadoFinal(true);
    automato.addEstado(estadoFinal);

    automato.setEstadoInicial(0);

    return automato;
}

Automato Automato::RealizarRepeticao() {
    Automato automato = this->RealizarOu();

    //list<Estado> listaEstados = automato.getListaEstados();

    automato.getListaEstados().front().addTransicao(Transicao('&',automato.getListaEstados().size()-1));

    //Estado estado = listaEstados.front();

    //estado.addTransicao(Transicao('&', listaEstados.size() - 1));

    return automato;

}

Automato Automato::RealizarUniao(Automato automato) {
    Automato automatoAux = Automato();

    Estado estadoInicial = Estado();
    estadoInicial.addTransicao(Transicao('&', 1));
    estadoInicial.addTransicao(Transicao('&', this->getListaEstados().size() + 1));
    estadoInicial.setEstadoFinal(false);

    automatoAux.addEstado(estadoInicial);

    list<Estado>::iterator iterator1;
    list<Estado> listaEstados = this->getListaEstados();

    for (iterator1 = listaEstados.begin(); iterator1 != listaEstados.end(); ++iterator1) {
        Estado estado = Estado();

        list<Transicao>::iterator iterator2;

        list<Transicao> listaTransicoes = iterator1->getListaTransicoes();

        for (iterator2 = listaTransicoes.begin(); iterator2 != listaTransicoes.end(); ++iterator2) {
            estado.addTransicao(Transicao(iterator2->getCaracterLido(), iterator2->getProxEstado() + 1));
        }

        if (iterator1->isEstadoFinal()) {
            estado.addTransicao(Transicao('&', listaEstados.size() + automato.getListaEstados().size() + 1));
        }

        estado.setEstadoFinal(false);
        automatoAux.addEstado(estado);
    }

    listaEstados = automato.getListaEstados();

    for (iterator1 = listaEstados.begin(); iterator1 != listaEstados.end(); ++iterator1) {
        Estado estado = Estado();

        list<Transicao> listaTransicoes = iterator1->getListaTransicoes();
        list<Transicao>::iterator iterator2;

        for (iterator2 = listaTransicoes.begin(); iterator2 != listaTransicoes.end(); ++iterator2) {
            estado.addTransicao(Transicao(iterator2->getCaracterLido(), iterator2->getProxEstado() + this->getListaEstados().size() + 1));
        }

        if (iterator1->isEstadoFinal()) {
            estado.addTransicao(Transicao('&', this->getListaEstados().size() + automato.getListaEstados().size() + 1));
        }

        estado.setEstadoFinal(false);
        automatoAux.addEstado(estado);
    }

    Estado estadoFinal = Estado();

    estadoFinal.setEstadoFinal(true);
    automatoAux.addEstado(estadoFinal);
    automatoAux.setEstadoInicial(0);

    return automatoAux;

}

void Automato::Imprimir() {
    vector<int> estadosFinais;

    list<Estado> listaEstados = this->getListaEstados();

    list<Estado>::iterator iterator;
    int count = 0;

    for (iterator = listaEstados.begin(); iterator != listaEstados.end(); ++iterator) {
        if (iterator->isEstadoFinal())
            estadosFinais.push_back(count);

        list<Transicao>::iterator iterator2;
        list<Transicao> listaTransicoes = iterator->getListaTransicoes();

        for (iterator2 = listaTransicoes.begin(); iterator2 != listaTransicoes.end(); ++iterator2) {
            cout << count << " --";
            if (iterator2->getCaracterLido() != '&')
                cout << " " << iterator2->getCaracterLido() << " ";
            else
                cout << "---";
            cout << "--> " << iterator2->getProxEstado() << "\n";
        }

        count++;
    }

    cout << "start: " << this->getEstadoInicial() << "\n";
    cout << "finish: ";

    for (size_t i = 0; i < estadosFinais.size() - 1; i++) {
        cout << estadosFinais[i] << ",";
    }
    cout << estadosFinais[estadosFinais.size() - 1] << "\n";
}




